/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package load.parent;
import core.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JOptionPane;
import view.GUI.LabelReader;
/**
 *
 * @author Ben
 */
public class Function extends StdNode{
    private List<InPort> params;
    private InPort content = new InPort(Function.class);
    private Wrapper.Signature sig;
    private Wrapper wrapper;
    private DispatcherPort resultChanged = new DispatcherPort();

    private TriggerPort argChanged = new TriggerPort() {
            @Override
            public void callInternal() throws ConnectException {
                    resultChanged.callTargets();
            }
        };

    private Object invokeMethod(){
        //read inports to args
        Object[] args = new Object[sig.getParams().length];
        for(int i = 0; i < args.length; i++){
            args[i] = params.get(i).getValue();
        }
        try{
           return wrapper.invoke(sig, args);
        }catch(Exception ex){
            JOptionPane.showMessageDialog(null,"Function: " + ex.getMessage(),
               LabelReader.getInstance().getString("Error"),JOptionPane.ERROR_MESSAGE);
            return null;
        }
    }

    public Function(Method m, Wrapper wrapper) {
        this(wrapper,new Wrapper.Signature(m.getName(),m.getParameterTypes(),m.getReturnType()));
    }

    public Function(Constructor ctr , Wrapper wrapper){
        this(wrapper,new Wrapper.Signature(ctr.getName(),ctr.getParameterTypes(),ctr.getDeclaringClass()));
    }

    public Function(Function f){
        this(f.wrapper, f.sig);
    }

    public Function(Wrapper wrap, Wrapper.Signature sign){
        this.autoPutPorts();
        OutPort result= new OutPort(Wrapper.classMapper(sign.getReturnType()), resultChanged) {
            @Override
            protected Object getValueInternal() {
                return invokeMethod();
            }
        };

        TriggerPort call = new TriggerPort() {
            @Override
            protected void callInternal() {
               invokeMethod();
            }
        };

        if(sign.getReturnType() != void.class){
            this.putPort("result", result);
        }else{
            this.putPort("call", call);
            this.ports.remove("resultChanged");
        }
        this.wrapper = wrap;
        this.sig = sign;
        params = new ArrayList<InPort>();
        //create the ports
        Class[] param = sig.getParams();
        for(int  i = 0; i < param.length; i++  ){
            InPort port = new InPort(Wrapper.classMapper(param[i]));
            this.putPort("arg" + i + "-" + param[i].getName(), port);
            params.add(port);
        }
    }
}
